package com.csj.mvvm.version

import android.app.Activity
import android.app.DownloadManager
import android.content.*
import android.database.ContentObserver
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.widget.ProgressBar
import androidx.core.content.FileProvider
import androidx.fragment.app.FragmentActivity
import com.csj.mvvm.App
import com.csj.mvvm.R
import com.csj.mvvm.databinding.DialogDownApkBinding
import com.csj.mvvm.utils.AppManager
import com.csj.mvvm.utils.CustomDialog
import com.csj.mvvm.utils.LogUtil
import com.csj.mvvm.utils.ToastUtil
import java.io.File
import java.lang.ref.WeakReference

/**
 * @describe 版本更新
 * Android11 应用安装 APK 的权限变得不再方便，需要重新启动相关应用才能生效
 */
class AppDownloadManager private constructor(activity: FragmentActivity) {
    private val apkName: String = App.instance.getString(R.string.app_name) + ".apk"
    private val weakReference: WeakReference<Activity>
    private val mDownloadManager: DownloadManager
    private val mDownLoadChangeObserver: DownloadChangeObserver
    private val mDownloadReceiver: DownloadReceiver
    private var mReqId: Long = 0
    private var mUpdateListener: OnUpdateListener? = null
    private val mContext: Context

    companion object {
        const val TAG = "AppDownloadManager"
        fun getInstance(activity: FragmentActivity) = AppDownloadManager(activity)
    }

    init {
        mContext = activity
        weakReference = WeakReference(activity)
        mDownloadManager =
            (weakReference.get() as FragmentActivity).getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        mDownLoadChangeObserver = DownloadChangeObserver(Handler())
        mDownloadReceiver = DownloadReceiver()
    }

    fun setUpdateListener(mUpdateListener: OnUpdateListener?) {
        this.mUpdateListener = mUpdateListener
    }

    fun downloadApk(
        apkUrl: String?,
        title: String?,
        desc: String?
    ) {
        // fix bug : 装不了新版本，在下载之前应该删除已有文件
        val apkFile = File(
            weakReference.get()!!.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
            apkName
        )
        if (apkFile.exists()) {
            apkFile.delete()
        }
        val request =
            DownloadManager.Request(Uri.parse(apkUrl))
        //设置title
        request.setTitle(title)
        // 设置描述
        request.setDescription(desc)
        // 完成后显示通知栏
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        request.setDestinationInExternalFilesDir(
            weakReference.get(),
            Environment.DIRECTORY_DOWNLOADS,
            apkName
        )
        request.setMimeType("application/vnd.android.package-archive")
        //
        mReqId = mDownloadManager.enqueue(request)
    }

    //版本更新弹窗
    fun showUpdateVersionDialog(
        apkUrl: String,
        note: String?,
        isExit: Boolean
    ) {
        val view = DialogDownApkBinding.inflate(LayoutInflater.from(mContext), null, false).root
        val pbUpdate = view.findViewById<ProgressBar>(R.id.pb_dialog)
        CustomDialog.Builder(mContext)
            .setWrapLp().setView(view).setViewBtn(view)
            .setMessage(if (TextUtils.isEmpty(note)) "发现新版本" else note)
            .setCancelable(!isExit)
            .setPositiveButton { dialog: DialogInterface?, i: Int ->
                if (apkUrl.contains(".apk")) {
                    pbUpdate.visibility = View.VISIBLE
                    setUpdateListener(object : OnUpdateListener {
                        override fun update(currentByte: Int, totalByte: Int) {
                            val progress = (currentByte * 100L / totalByte).toInt()
                            pbUpdate.progress = progress
                        }
                    })
                    downloadApk(apkUrl, "版本更新", if (TextUtils.isEmpty(note)) "发现新版本" else note)
                    //                        dialog.dismiss();
                } else {
                    val intent = Intent()
                    intent.action = Intent.ACTION_VIEW
                    val content_url = Uri.parse(apkUrl)
                    intent.data = content_url
                    mContext.startActivity(intent)
                }
            }
            .setNegativeButton { dialog: DialogInterface?, i: Int ->
                if (isExit) {
                    AppManager.instance.appExit()
                }
            }
            .show()
    }

    /**
     * 取消下载
     */
    fun cancel() {
        mDownloadManager.remove(mReqId)
    }

    /**
     * 对应 [Activity]
     */
    fun create() {
        //设置监听Uri.parse("content://downloads/my_downloads")
        weakReference.get()!!.contentResolver.registerContentObserver(
            Uri.parse("content://downloads/my_downloads"), true,
            mDownLoadChangeObserver
        )
        // 注册广播，监听APK是否下载完成
        weakReference.get()!!.registerReceiver(
            mDownloadReceiver,
            IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
        )
    }

    /**
     * 对应[Activity]
     */
    fun destroy() {
        LogUtil.e("mDownLoadManage onDestroy")
        weakReference.get()!!.contentResolver.unregisterContentObserver(mDownLoadChangeObserver)
        weakReference.get()!!.unregisterReceiver(mDownloadReceiver)
    }

    private fun updateView() {
        val bytesAndStatus = intArrayOf(0, 0, 0)
        val query = DownloadManager.Query().setFilterById(mReqId)
        var c: Cursor? = null
        try {
            c = mDownloadManager.query(query)
            if (c != null && c.moveToFirst()) {
                //已经下载的字节数
                bytesAndStatus[0] =
                    c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                //总需下载的字节数
                bytesAndStatus[1] =
                    c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                //状态所在的列索引
                bytesAndStatus[2] = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))
            }
        } finally {
            c?.close()
        }
        mUpdateListener?.update(bytesAndStatus[0], bytesAndStatus[1])
        LogUtil.e(TAG, "下载进度：" + bytesAndStatus[0] + "/" + bytesAndStatus[1] + "")
    }

    internal inner class DownloadChangeObserver
    /**
     * Creates a content observer.
     *
     * @param handler The handler to run [.onChange] on, or null if none.
     */
        (handler: Handler?) : ContentObserver(handler) {
        override fun onChange(selfChange: Boolean) {
            super.onChange(selfChange)
            updateView()
        }
    }

    internal inner class DownloadReceiver : BroadcastReceiver() {
        override fun onReceive(
            context: Context,
            intent: Intent
        ) {
            val haveInstallPermission: Boolean
            // 兼容Android 8.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

                //先获取是否有安装未知来源应用的权限
                haveInstallPermission = context.packageManager.canRequestPackageInstalls()
                if (!haveInstallPermission) { //没有权限
                    // 弹窗，并去设置页面授权
                    val listener: AndroidOInstallPermissionListener =
                        object : AndroidOInstallPermissionListener {
                            override fun permissionSuccess() {
                                installApk(context, intent)
                            }

                            override fun permissionFail() {
                                ToastUtil.showToast("授权失败")
                            }
                        }
                    AndroidOPermissionActivity.sListener = listener
                    val intent1 = Intent(context, AndroidOPermissionActivity::class.java)
                    context.startActivity(intent1)
                } else {
                    installApk(context, intent)
                }
            } else {
                installApk(context, intent)
            }
        }
    }

    /**
     * @param context
     * @param intent
     */
    private fun installApk(context: Context, intent: Intent) {
        val completeDownLoadId =
            intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
        LogUtil.e(TAG, "收到广播")
        val uri: Uri
        val intentInstall = Intent()
        intentInstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intentInstall.action = Intent.ACTION_VIEW
        if (completeDownLoadId == mReqId) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // 6.0以下
                uri = mDownloadManager.getUriForDownloadedFile(completeDownLoadId)
            } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { // 6.0 - 7.0
                val apkFile =
                    queryDownloadedApk(context, completeDownLoadId)
                uri = Uri.fromFile(apkFile)
            } else { // Android 7.0 以上
                uri = FileProvider.getUriForFile(
                    context,
                    context.packageName + ".FileProvider",
                    File(
                        context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
                        apkName
                    )
                )
                intentInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            }

            // 安装应用
            LogUtil.e(TAG, "下载完成了")
            intentInstall.setDataAndType(uri, "application/vnd.android.package-archive")
            context.startActivity(intentInstall)
        }
    }

    //通过downLoadId查询下载的apk，解决6.0以后安装的问题
    fun queryDownloadedApk(
        context: Context,
        downloadId: Long
    ): File? {
        var targetApkFile: File? = null
        val downloader =
            context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        if (downloadId != -1L) {
            val query = DownloadManager.Query()
            query.setFilterById(downloadId)
            query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL)
            val cur = downloader.query(query)
            if (cur != null) {
                if (cur.moveToFirst()) {
                    val uriString =
                        cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
                    if (!TextUtils.isEmpty(uriString)) {
                        targetApkFile = File(Uri.parse(uriString).path!!)
                    }
                }
                cur.close()
            }
        }
        return targetApkFile
    }

    interface OnUpdateListener {
        fun update(currentByte: Int, totalByte: Int)
    }

    interface AndroidOInstallPermissionListener {
        fun permissionSuccess()
        fun permissionFail()
    }

}
